package com.framework.view.indicator.indicators;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.view.MotionEvent;
import android.view.View;

import com.framework.view.indicator.IPageIndicator;
import com.framework.view.indicator.indicators.configs.PointIndicatorConfig;
import com.framework.view.indicator.model.IndicatorShapeType;
import com.framework.view.indicator.model.PositionInfo;
import com.framework.view.indicator.model.StrokeType;

import java.util.ArrayList;
import java.util.List;

/**
 * 点状指示器
 *
 * @author liangzx
 * @version 1.0
 * @time 2019-12-24 16:57
 **/
public class PointIndicatorView extends View implements IPageIndicator<PointIndicatorConfig> {

    /**
     * 指示器配置
     */
    private PointIndicatorConfig mConfig;
    /**
     * 点的位置列表
     */
    private List<RectF> mPointRects;
    /**
     * 画笔
     */
    private Paint mPaint;
    /**
     * 总数
     */
    private int mTotalCount;
    /**
     * 当前选中位置
     */
    private int mCurPosition;
    /**
     * 内部宽度
     */
    private int mContentWidth;
    /**
     * 内部高度
     */
    private int mContentHeight;
    /**
     * 用于记录跟随手指滑动的坐标
     */
    private float mIndicatorX = -1F;
    private OnClickListener mClickListener;

    public PointIndicatorView(Context context) {
        super(context);
    }

    @Override
    public void init(PointIndicatorConfig config, int totalCount, int position) {
        mConfig = config;
        mTotalCount = totalCount;
        mCurPosition = position;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPointRects = new ArrayList<>(totalCount);
    }

    /**
     * 回调点击动作
     *
     * @param listener
     */
    public void addCallBack(OnClickListener listener) {
        this.mClickListener = listener;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawPoint(canvas);
        drawIndicator(canvas);
    }

    /**
     * 绘制点
     *
     * @param canvas
     */
    private void drawPoint(Canvas canvas) {
        boolean needStroke = mConfig.getStrokeStyle() == StrokeType.ALL
                || mConfig.getStrokeStyle() == StrokeType.JUST_NORMAL;
        mPaint.setStyle(needStroke ? Paint.Style.STROKE : Paint.Style.FILL);
        mPaint.setStrokeWidth(needStroke ? mConfig.getStrokeWidth() : 0);
        for (int i = 0; i < mPointRects.size(); i++) {
            RectF rectF = mPointRects.get(i);
            mPaint.setColor(mConfig.getNormalColor());
            if (mConfig.getShapeType() == IndicatorShapeType.RECT
                    || mConfig.getShapeType() == IndicatorShapeType.ROUND_RECT) {
                float curWid = mConfig.getNormalWidth() - (needStroke ? mConfig.getStrokeWidth() : 0);
                float curHeight = mConfig.getNormalHeight() - (needStroke ? mConfig.getStrokeWidth() : 0);
                float left = (rectF.left + rectF.right) / 2 - curWid / 2;
                float top = (rectF.top + rectF.bottom) / 2 - curHeight / 2;
                float right = left + curWid;
                float bottom = top + curHeight;
                if (mConfig.getShapeType() == IndicatorShapeType.RECT) {
                    canvas.drawRect(left, top, right, bottom, mPaint);
                } else {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        canvas.drawRoundRect(left, top, right, bottom, mConfig.getRoundRadius(), mConfig.getRoundRadius(), mPaint);
                    } else {
                        RectF result = new RectF(left, top, right, bottom);
                        canvas.drawRoundRect(result, mConfig.getRoundRadius(), mConfig.getRoundRadius(), mPaint);
                    }
                }
            } else if (mConfig.getShapeType() == IndicatorShapeType.CIRCLE) {
                float cx = (rectF.left + rectF.right) / 2;
                float cy = (rectF.top + rectF.bottom) / 2;
                canvas.drawCircle(cx, cy, (mConfig.getNormalWidth() - (needStroke ? mConfig.getStrokeWidth() : 0)) / 2, mPaint);
            }
        }
    }

    /**
     * 绘制指示器-即随手指滑动的效果
     *
     * @param canvas
     */
    private void drawIndicator(Canvas canvas) {
        boolean needStroke = mConfig.getStrokeStyle() == StrokeType.ALL
                || mConfig.getStrokeStyle() == StrokeType.JUST_SELECTED;
        mPaint.setStyle(needStroke ? Paint.Style.STROKE : Paint.Style.FILL);
        mPaint.setStrokeWidth(needStroke ? mConfig.getStrokeWidth() : 0);
        RectF rectF = mPointRects.get(mCurPosition);
        mPaint.setColor(mConfig.getSelectedColor());
        if (mIndicatorX == -1) {
            mIndicatorX = rectF.left + rectF.width() / 2;
        }
        if (mConfig.getShapeType() == IndicatorShapeType.RECT
                || mConfig.getShapeType() == IndicatorShapeType.ROUND_RECT) {
            float curWid = mConfig.getSelectedWidth() - (needStroke ? mConfig.getStrokeWidth() : 0);
            float curHeight = mConfig.getSelectedHeight() - (needStroke ? mConfig.getStrokeWidth() : 0);
            float left = mIndicatorX - curWid / 2;
            float top = (rectF.top + rectF.bottom) / 2 - curHeight / 2;
            float right = left + curWid;
            float bottom = top + curHeight;
            if (mConfig.getShapeType() == IndicatorShapeType.RECT) {
                canvas.drawRect(left, top, right, bottom, mPaint);
            } else {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    canvas.drawRoundRect(left, top, right, bottom, mConfig.getRoundRadius(), mConfig.getRoundRadius(), mPaint);
                } else {
                    RectF result = new RectF(left, top, right, bottom);
                    canvas.drawRoundRect(result, mConfig.getRoundRadius(), mConfig.getRoundRadius(), mPaint);
                }
            }
        } else if (mConfig.getShapeType() == IndicatorShapeType.CIRCLE) {
            float cy = (rectF.top + rectF.bottom) / 2;
            canvas.drawCircle(mIndicatorX, cy, (mConfig.getNormalWidth() - (needStroke ? mConfig.getStrokeWidth() : 0)) / 2, mPaint);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (0 >= mTotalCount) {
            return;
        }
        mContentWidth = Math.max(mConfig.getNormalWidth(), mConfig.getSelectedWidth()) * mTotalCount
                + (mConfig.getPendingLeft() + mConfig.getPendingRight()) * (mTotalCount - 1);
        mContentHeight = Math.max(mConfig.getNormalHeight(), mConfig.getSelectedHeight());
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (null == mPointRects) {
            mPointRects = new ArrayList<>(mTotalCount);
        } else {
            mPointRects.clear();
        }
        int maxItemWidth = Math.max(mConfig.getNormalWidth(), mConfig.getSelectedWidth());
        int panding = mConfig.getPendingLeft() + mConfig.getPendingRight();
        int itemTop = (getHeight() - mContentHeight) / 2;//实现竖向居中
        int itemBottom = itemTop + mContentHeight;//实现竖向居中
        int firstX = (getWidth() - mContentWidth) / 2;//绘制初始横坐标，实现居中

        for (int i = 0; i < mTotalCount; i++) {
            RectF item = new RectF();
            item.top = itemTop;
            item.bottom = itemBottom;
            item.left = firstX + i * (maxItemWidth + panding);
            item.right = item.left + maxItemWidth;
            mPointRects.add(item);
        }
    }

    /**
     * 测量高度
     *
     * @param heightMeasureSpec
     * @return
     */
    private int measureHeight(int heightMeasureSpec) {
        int size = MeasureSpec.getSize(heightMeasureSpec);
        int mode = MeasureSpec.getMode(heightMeasureSpec);
        int result = size;

        switch (mode) {
            case MeasureSpec.AT_MOST://wrap_content
                int width = Math.max(mConfig.getNormalHeight(), mConfig.getSelectedHeight());
                result = Math.min(width, size);
                break;
            case MeasureSpec.UNSPECIFIED://无限制，View对尺寸没有任何限制，View设置为多大就应当为多大
                result = size;
                break;
        }
        return result;
    }

    @Override
    public void updateTitlePositions(List<PositionInfo> positions) {
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (null == mPointRects || mPointRects.isEmpty()) {
            return;
        }
        int currentPosition = Math.min(mPointRects.size() - 1, position);
        int nextPosition = Math.min(mPointRects.size() - 1, position + 1);
        RectF current = mPointRects.get(currentPosition);
        RectF next = mPointRects.get(nextPosition);
        mIndicatorX = current.left + current.width() / 2 + (next.left - current.left) * mConfig.getStartInterpolator().getInterpolation(positionOffset);
        invalidate();
    }

    @Override
    public void onPageSelected(int position) {
        RectF current = mPointRects.get(position);
        mCurPosition = position;
        mIndicatorX = current.left + current.width() / 2;
        invalidate();
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

    @Override
    public void onEntering(int index, int totalCount, float enterPercent, boolean leftToRight) {
    }

    @Override
    public void onLeaving(int index, int totalCount, float leavePercent, boolean leftToRight) {
    }

    @Override
    public void onSelected(int index, int totalCount) {
        mCurPosition = index;
    }

    @Override
    public void onCancelSelected(int index, int totalCount) {
    }

//    @Override
//    protected void onDetachedFromWindow() {
//        super.onDetachedFromWindow();
//        if (null != mPointRects) {
//            mPointRects.clear();
//        }
//    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            float y = event.getY();
            float x = event.getX();
            if (null != mPointRects && !mPointRects.isEmpty()) {
                int index = 0;
                for (RectF item : mPointRects) {
                    if (item.contains(x, y)) {
                        if (null != mClickListener) {
                            setTag(index);
                            mClickListener.onClick(this);
                        }
                        return super.onTouchEvent(event);
                    }
                    index++;
                }
            }
        }
        return true;
    }
}
